using System;
using CfgTable;
using Cinemachine;
using Cysharp.Threading.Tasks;
using IQIGame.Onigao.Framework;
using IQIGame.Onigao.Game;
using IQIGame.Rendering;
using UnityEngine;

namespace IQIGame.Onigao.GamePlay
{
    public class BattleRenderSceneController : BattleRenderBaseController
    {
        private string sceneName;

        public float mapRadius;
        private float cameraRange => this.mapRadius;
        private float cameraMidRange => this.mapRadius * 4 / 5;
        private float cameraFarRange => this.mapRadius * 2 / 3;

        private UnitViewComponent mCurSelectUnit;
        private bool mDraging;

        private ObjectBinding m_ObjectBinding;

        #region ObjectBinding Generate
            public Cinemachine.CinemachineBrain cinemachineBrain { protected set; get; }
            public Cinemachine.CinemachineVirtualCamera vc_Main { protected set; get; }
            public Cinemachine.CinemachineVirtualCamera vc_Mid { protected set; get; }
            public Cinemachine.CinemachineVirtualCamera vc_Far { protected set; get; }
            public Cinemachine.CinemachineVirtualCamera vc_Character { protected set; get; }
            public UnityEngine.Playables.PlayableDirector tl_MoveFocus { protected set; get; }
            public UnityEngine.Transform roleRoot { protected set; get; }
            public UnityEngine.Transform targetMain { protected set; get; }
            public UnityEngine.Transform targetSelect { protected set; get; }
            public UnityEngine.Transform characterFollow { protected set; get; }
            public Cinemachine.CinemachineVirtualCamera vc_Monster { protected set; get; }
            public UnityEngine.Transform roleFollow { protected set; get; }
            public UnityEngine.GameObject scene { protected set; get; }
            public virtual void InitBinding(ObjectBinding __binding)
            {
                __binding.TryGetVariableValue<Cinemachine.CinemachineBrain>("cinemachineBrain", out var __tbv0);
                this.cinemachineBrain = __tbv0;
                __binding.TryGetVariableValue<Cinemachine.CinemachineVirtualCamera>("vc_Main", out var __tbv1);
                this.vc_Main = __tbv1;
                __binding.TryGetVariableValue<Cinemachine.CinemachineVirtualCamera>("vc_Mid", out var __tbv2);
                this.vc_Mid = __tbv2;
                __binding.TryGetVariableValue<Cinemachine.CinemachineVirtualCamera>("vc_Far", out var __tbv3);
                this.vc_Far = __tbv3;
                __binding.TryGetVariableValue<Cinemachine.CinemachineVirtualCamera>("vc_Character", out var __tbv4);
                this.vc_Character = __tbv4;
                __binding.TryGetVariableValue<UnityEngine.Playables.PlayableDirector>("tl_MoveFocus", out var __tbv5);
                this.tl_MoveFocus = __tbv5;
                __binding.TryGetVariableValue<UnityEngine.Transform>("roleRoot", out var __tbv6);
                this.roleRoot = __tbv6;
                __binding.TryGetVariableValue<UnityEngine.Transform>("targetMain", out var __tbv7);
                this.targetMain = __tbv7;
                __binding.TryGetVariableValue<UnityEngine.Transform>("targetSelect", out var __tbv8);
                this.targetSelect = __tbv8;
                __binding.TryGetVariableValue<UnityEngine.Transform>("characterFollow", out var __tbv9);
                this.characterFollow = __tbv9;
                __binding.TryGetVariableValue<Cinemachine.CinemachineVirtualCamera>("vc_Monster", out var __tbv10);
                this.vc_Monster = __tbv10;
                __binding.TryGetVariableValue<UnityEngine.Transform>("roleFollow", out var __tbv11);
                this.roleFollow = __tbv11;
                __binding.TryGetVariableValue<UnityEngine.GameObject>("scene", out var __tbv12);
                this.scene = __tbv12;
            }
            #endregion ObjectBinding Generate

        /// <summary>
        ///     场景加载接口
        /// </summary>
        private BattleSceneLoader m_GameSceneLoader = new BattleSceneLoader();

        private EBattleCameraState mCurCameraState;
        private EBattleCameraState mTargetCameraState;

        private ColorAdjustmentsVolume sceneLightVolume;
        private float defaultLightValue;
        private float targetLightValue;

        public async UniTask FirstEnterScene()
        {
            m_GameSceneLoader.AddAsyncPreloadFirst(PreloadScene);
            await ManagerCenter.Scene.LoadAbSceneAsync(this.sceneName, UnityEngine.SceneManagement.LoadSceneMode.Additive, m_GameSceneLoader);
        }

        private UniTask PreloadScene()
        {
            var binding = GameObject.Find("ObjectBinding");
            if (binding == null)
            {
                LogGame.LogError("Can't find ObjectBinding.");
                return UniTask.CompletedTask;
            }
            m_ObjectBinding = binding.GetComponent<ObjectBinding>();

            try
            {
                this.InitBinding(this.m_ObjectBinding);
            }
            catch
            {
                LogGame.LogError("战斗场景Objectbinding失效，检查binding");
            }

            return UniTask.CompletedTask;
        }

        public async UniTask Initialize(BattleRenderContrller rRenderCtrl, CfgBattleScene rConfig)
        {
            this.sceneName = rConfig.BattleSceneFile;
            this.mapRadius = rConfig.BattleRadius / 1000f;
            await base.Initialize(rRenderCtrl);
            this.mCtrl = rRenderCtrl;
            await this.FirstEnterScene();
            HUDNumberRender.Instance.Initialize(PathConstant.GetHUDConfigPath(), this.cinemachineBrain.GetComponent<Camera>());
            this.SetCameraState(EBattleCameraState.Main);
        }

        public async UniTask Restart(CfgBattleScene rConfig)
        {
            if (this.sceneName != rConfig.BattleSceneFile)
            {
                this.Dispose();
                this.sceneName = rConfig.BattleSceneFile;
                await this.FirstEnterScene();
            }
            this.mapRadius = rConfig.BattleRadius / 1000f;
            this.SetCameraState(EBattleCameraState.Main);
        }

        protected override void OnUpdate(float deltaTime)
        {
            base.OnUpdate(deltaTime);
            if (this.sceneLightVolume != null)
            {
                var fCurLightValue = this.sceneLightVolume.postExposure.value;
                if (Math.Abs(fCurLightValue - this.targetLightValue) > 0.01f)
                {
                    this.SetLight(Mathf.Lerp(fCurLightValue, this.targetLightValue, 0.1f));
                }
                else if (fCurLightValue != this.targetLightValue)
                {
                    this.SetLight(this.targetLightValue);
                }
            }

            if (this.mCurCameraState != this.mTargetCameraState)
            {
                this.mCurCameraState = this.mTargetCameraState;
                this.vc_Main.gameObject.SetActive(this.mCurCameraState == EBattleCameraState.Main);
                this.vc_Monster.gameObject.SetActive(this.mCurCameraState == EBattleCameraState.Monster);
                this.vc_Mid.gameObject.SetActive(this.mCurCameraState == EBattleCameraState.Mid);
                this.vc_Far.gameObject.SetActive(this.mCurCameraState == EBattleCameraState.Far);
                this.vc_Character.gameObject.SetActive(this.mCurCameraState == EBattleCameraState.Character);

                this.DragCamera(Vector2.zero);
                this.mDraging = false;
                if (this.mCurCameraState == EBattleCameraState.Main)
                {
                    this.targetMain.transform.position = this.mCurSelectUnit?.position ?? Vector3.zero;
                }
            }
        }

        public void CameraOnSelectCharacter(UnitViewComponent rViewComp)
        {
            this.mCurSelectUnit = rViewComp;
            this.targetMain.transform.position = this.mCurSelectUnit?.position ?? Vector3.zero;
            this.SetCameraState(this.mCurSelectUnit == null || this.mCurSelectUnit.unit.teamIndex == BattleConst.TeamRedIndex ? EBattleCameraState.Main : EBattleCameraState.Monster);
        }

        public void CameraOnCharacterMove(UnitViewComponent rViewComp)
        {
            if (this.mCurSelectUnit == rViewComp && !this.mDraging)
            {
                this.targetMain.transform.position = this.mCurSelectUnit?.position ?? Vector3.zero;
            }
        }

        public void ResetCamera()
        {
            this.SetCameraState(this.mCurSelectUnit == null || this.mCurSelectUnit.unit.teamIndex == BattleConst.TeamRedIndex ? EBattleCameraState.Main : EBattleCameraState.Monster);
            this.mDraging = false;
            this.targetMain.transform.position = this.mCurSelectUnit?.position ?? Vector3.zero;
            // 因为具体切换virtualcamera的行为在update中，这里不能对位置修改
            // this.roleFollow.transform.localPosition = Vector3.zero;
            // this.characterFollow.transform.localPosition = Vector3.zero;
        }

        public void SetMainCameraDistance(float distance)
        {
            distance = Math.Clamp(distance, 5, 10);
            CinemachineComponentBase componentBase = this.vc_Main.GetCinemachineComponent(CinemachineCore.Stage.Body);
            if (componentBase is CinemachineFramingTransposer framing)
            {
                framing.m_CameraDistance = distance;
            }
        }

        public void DragCamera(Vector2 rDrag)
        {
            this.mDraging = true;
            var rCameraRotation = ManagerCenter.UI.MainCamera.transform.rotation;
            var rTargetTrans = this.targetMain;
            var rTargetPos = rTargetTrans.position;

            var rDelta = BattleClientUtil.ScreenDirToWorld(rCameraRotation, rDrag);

            var fRange = 0f;
            var rCurVC = this.vc_Main;
            switch (this.mCurCameraState)
            {
                case EBattleCameraState.Main:
                    fRange = this.cameraRange;
                    break;
                case EBattleCameraState.Mid:
                case EBattleCameraState.Monster:
                    fRange = this.cameraMidRange;
                    rCurVC = this.vc_Mid;
                    break;
                case EBattleCameraState.Far:
                    fRange = this.cameraFarRange;
                    rCurVC = this.vc_Far;
                    break;
            }
            var rFraming = rCurVC.GetCinemachineComponent(CinemachineCore.Stage.Body) as CinemachineFramingTransposer;
            var rDis = rFraming != null ? rFraming.m_CameraDistance : 0;

            var fRate = rDis * BattleConst.CameraMoveRate;
            rTargetPos = rTargetTrans.position + rDelta * fRate;
            if (fRange > 0)
            {
                rTargetPos = Vector3.ClampMagnitude(rTargetPos, fRange);
            }
            rTargetTrans.position = rTargetPos;
        }

        public void SetCameraState(EBattleCameraState state)
        {
            this.mTargetCameraState = state;
        }

        public void SetLight(bool bOn)
        {
            if (this.sceneLightVolume == null)
            {
                this.sceneLightVolume = GameRenderPostProcess.Instance.GetVoume(GameRender.CameraType.MainCamera, UnityEngine.Rendering.Universal.RenderPassEvent.AfterRenderingSkybox, typeof(Rendering.ColorAdjustmentsVolume))
                    as ColorAdjustmentsVolume;
                this.defaultLightValue = this.sceneLightVolume?.postExposure.value ?? 0;
            }
            if (this.sceneLightVolume != null)
            {
                this.targetLightValue = bOn ? this.defaultLightValue : 0f;
            }
        }

        public void SetLight(float fValue)
        {
            if (this.sceneLightVolume == null)
            {
                this.sceneLightVolume = GameRenderPostProcess.Instance.GetVoume(GameRender.CameraType.MainCamera, UnityEngine.Rendering.Universal.RenderPassEvent.AfterRenderingSkybox, typeof(Rendering.ColorAdjustmentsVolume))
                    as ColorAdjustmentsVolume;
                this.defaultLightValue = this.sceneLightVolume?.postExposure.value ?? 0;
            }
            if (this.sceneLightVolume != null)
            {
                this.sceneLightVolume.postExposure.value = fValue;
            }
        }

        protected override void OnDispose()
        {
            HUDNumberRender.Instance.Dispose();
            ManagerCenter.Scene.UnloadSceneAsync(this.sceneName);
        }

        public enum EBattleCameraState
        {
            None,
            Main,
            Monster,
            Mid,
            Far,
            Character,
        }
    }
}